home *** CD-ROM | disk | FTP | other *** search
-
- #pragma segment TAR
-
- /*
- * Macintosh Tar
- *
- * Modified by Craig Ruff for use on the Macintosh.
- */
- /*
- * Extract files from a tar archive.
- *
- * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
- *
- * @(#) extract.c 1.17 86/10/29 Public Domain - gnu
- */
-
- #include "tar.h"
- #include "stat.h"
- #include <string.h>
-
- extern union record *head; /* Points to current tape header */
- extern struct
- {
- long st_size;
- long st_mtime;
- } hstat; /* Fake stat struct for compat. */
-
- Boolean ExtractArchive();
- extern void PrintHeader();
- extern Boolean SkipFile();
-
- int MakeDirs(); /* Makes required directories */
-
- #ifdef TCLAPPL
-
- /*
- * Extract - extract the entire archive
- */
- Extract() {
- Point where;
- SFReply reply;
- char name[256];
- extern WindowPtr theFeedbackWindow;
-
- /*
- * Use the standard file dialog to select the archive.
- */
- where.h = where.v = 75;
- MyGetFile(where, "\pTar Archive:", nil, -1, nil, nil, &reply);
- if (!reply.good)
- return;
-
- /*
- * Remember the VRefNum and Name for OpenArchive.
- * Find out where to put the extracted files.
- */
- arName = reply.fName;
- WDDirVRef(reply.vRefNum, &arVRefNum, &arDirID);
- if (! GetFolderPathName("Extraction Directory:", name, &dirVRefNum, &dirDirID))
- return;
-
- /*
- * Extract and print the files as found in the archive.
- */
- if (WindInit())
- return;
- /*TGE*/ UBegYield();
-
- /*TGE*/ ShowFeedback();
-
- /*TGE*/ SetPort(theFeedbackWindow);
- TextFace(underline);
- WPrintf(header);
- /*TGE*/ SetPort(theFeedbackWindow);
- TextFace(0);
-
- ReadAnd(ExtractArchive);
- CloseArchive();
-
- WPrintf("--- tar extraction completed.");
-
- WindEnd(autoPage);
- /*TGE*/ UEndYield();
- }
-
- #endif
-
- AEExtract(myFSS)
- FSSpec *myFSS;
- {
- int myerr;
- char name[256];
- extern WindowPtr theFeedbackWindow;
-
- #ifdef TCLAPPL
- if (! GetFolderPathName("Extraction Directory:", name, &dirVRefNum, &dirDirID))
- {
- Feedback("Tar extract canceled.");
- return noErr;
- }
- #else
- dirDirID = myFSS->parID;
- dirVRefNum = myFSS->vRefNum;
- #endif
-
- /*
- * Extract and print the files as found in the archive.
- */
- if (WindInit())
- return;
-
- /*
- ** Remember the VRefNum and Name for OpenArchive.
- ** Find out where to put the extracted files.
- */
-
- arName = myFSS->name;
- arDirID = myFSS->parID;
- arVRefNum = myFSS->vRefNum;
-
- UBegYield();
-
- ShowFeedback();
-
- SetPort(theFeedbackWindow);
- TextFace(underline);
- WPrintf(header);
- SetPort(theFeedbackWindow);
- TextFace(0);
-
- ReadAnd(ExtractArchive);
- CloseArchive();
-
- WPrintf("--- tar extraction completed.");
-
- WindEnd(autoPage);
- UEndYield();
-
- return noErr;
- }
-
- Cmd_Extract(clientData, interp, argc, argv)
- char *clientData;
- Tcl_Interp *interp;
- int argc;
- char *argv[];
- {
- int arg_index;
- short vref;
- long dirid;
- char pascal_name[256], *archive_name, *dir_name, *ptr;
- struct stat arstat, dirstat;
- char saveType[8], saveCreator[8], buf[8];
- Boolean save_cvtNl = cvtNl;
- #pragma unused (clientData)
-
- extern WindowPtr theFeedbackWindow;
-
- if (argc < 3)
- {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " ?options...? archive_filename extract_dirname\"", (char *) NULL);
- return TCL_ERROR;
- }
-
- memcpy(saveType, fdType, 4);
- memcpy(saveCreator, fdCreator, 4);
- cvtNl = false;
-
- for ( arg_index = 1 ; arg_index < argc ; ++arg_index )
- {
- if (argv[arg_index][0] != '-')
- break;
-
- if (argv[arg_index][1] == '-' && argv[arg_index][2] == '\0')
- break;
-
- if (argv[arg_index][1] == 't' && argv[arg_index][2] == '\0')
- {
- sprintf(buf, "%-4.4s", argv[arg_index+1]);
- memcpy(fdType, buf, 4);
- ++arg_index;
- }
- else if (argv[arg_index][1] == 'c' && argv[arg_index][2] == '\0')
- {
- sprintf(buf, "%-4.4s", argv[arg_index+1]);
- memcpy(fdCreator, buf, 4);
- ++arg_index;
- }
- else if (argv[arg_index][1] == 'a' && argv[arg_index][2] == '\0')
- {
- cvtNl = true;
- }
- else
- {
- Tcl_AppendResult(interp, "invalid option \"", argv[arg_index],
- "\"", (char *) NULL);
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
- return TCL_ERROR;
- }
- }
-
- if (arg_index >= argc)
- {
- Tcl_AppendResult(interp, "missing archive name argument", (char *) NULL);
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
- return TCL_ERROR;
- }
-
- archive_name = argv[arg_index++];
-
- if (arg_index >= argc)
- {
- Tcl_AppendResult(interp, "missing extract directory argument", (char *) NULL);
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
- return TCL_ERROR;
- }
-
- if ( stat( archive_name, &arstat ) < 0)
- {
- Tcl_AppendResult(interp, "could not locate archive file \"", archive_name,
- "\"", (char *) NULL);
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
- return TCL_ERROR;
- }
-
- dir_name = argv[arg_index++];
-
- if ( stat( dir_name, &dirstat ) < 0)
- {
- Tcl_AppendResult(interp, "could not locate extract directory \"", dir_name,
- "\"", (char *) NULL);
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
- return TCL_ERROR;
- }
-
- if ( ! S_ISDIR(dirstat.st_mode) )
- {
- Tcl_AppendResult(interp, "extract directory \"", dir_name,
- "\" not a directory ", (char *) NULL);
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
- return TCL_ERROR;
- }
-
- dirVRefNum = dirstat.st_dev;
- dirDirID = dirstat.st_ino;
-
- /*
- * Extract and print the files as found in the archive.
- */
- WindInit();
-
- arDirID = arstat.st_parid;
- arVRefNum = arstat.st_dev;
- ptr = strrchr(archive_name, ':');
- if (ptr == NULL)
- strcpy(pascal_name, archive_name);
- else
- strcpy(pascal_name, ptr + 1);
- c2pstr(pascal_name);
- arName = pascal_name;
-
- tar_scripting = 1;
- tar_interp = interp;
-
- UBegYield();
-
- SetPort(theFeedbackWindow);
- TextFace(underline);
- WPrintf(header);
- SetPort(theFeedbackWindow);
- TextFace(0);
-
- ReadAnd(ExtractArchive);
- CloseArchive();
-
- WPrintf("--- tar extraction completed.");
-
- WindEnd(autoPage);
- UEndYield();
-
- tar_scripting = 0;
- tar_interp = NULL;
-
- memcpy(fdType, saveType, 4);
- memcpy(fdCreator, saveCreator, 4);
- cvtNl = save_cvtNl;
-
- return TCL_OK;
- }
-
- /*
- * Extract a file from the archive.
- */
- Boolean
- ExtractArchive()
- {
- register char *data;
- register char *p;
- union record *rec;
- int i, namelen;
- Boolean errFound = false;
- long check, written;
- long size;
- OSErr err;
- char macName[256];
- HParamBlockRec dpb;
- HParamBlockRec fpb;
- char *routine = "\pExtractArchive";
-
- SaveRec(&head); /* Make sure it sticks around */
- UseRec(head); /* And go past it in the archive */
- DecodeHeader(head, &hstat, 1); /* Snarf fields */
-
- /* Print the record from 'head' and 'hstat' */
- PrintHeader();
-
- switch (head->header.linkflag) {
- default:
- WPrintf("Unknown file type %d for %s",
- head->header.linkflag, head->header.name);
- break;
-
- case LF_OLDNORMAL:
- case LF_NORMAL:
- /*
- * Appears to be a file.
- * See if it's really a directory.
- */
- namelen = strlen(head->header.name) - 1;
- if (head->header.name[namelen] == '/')
- goto really_dir;
-
- FixName(head->header.name, macName);
- again_file:
- fpb.fileParam.ioCompletion = nil;
- fpb.fileParam.ioNamePtr = macName;
- fpb.fileParam.ioVRefNum = dirVRefNum;
- fpb.fileParam.ioFVersNum = 0;
- fpb.fileParam.ioDirID = dirDirID;
- err = PBHCreate(&fpb, false);
- if (err == noErr) {
- fpb.fileParam.ioCompletion = nil;
- fpb.fileParam.ioNamePtr = macName;
- fpb.fileParam.ioVRefNum = dirVRefNum;
- fpb.fileParam.ioDirID = dirDirID;
- fpb.fileParam.ioFVersNum = 0;
- fpb.fileParam.ioFDirIndex = 0;
- if (PBHGetFInfo(&fpb, false)) {
- OSAlert(routine, "\pPBHGetFInfo", macName,
- fpb.fileParam.ioResult);
- goto doNext;
- }
-
- strncpy((char *)&fpb.fileParam.ioFlFndrInfo.fdCreator, fdCreator, 4);
- strncpy((char *)&fpb.fileParam.ioFlFndrInfo.fdType, fdType, 4);
- fpb.fileParam.ioCompletion = nil;
- fpb.fileParam.ioNamePtr = macName;
- fpb.fileParam.ioVRefNum = dirVRefNum;
- fpb.fileParam.ioDirID = dirDirID;
- fpb.fileParam.ioFVersNum = 0;
- if (PBHSetFInfo(&fpb, false)) {
- OSAlert(routine, "\pPBHSetFInfo", macName,
- fpb.fileParam.ioResult);
- goto doNext;
- }
-
- fpb.ioParam.ioPermssn = fsWrPerm;
- fpb.ioParam.ioMisc = nil;
- err = PBHOpen(&fpb, false);
- }
-
- if (err != noErr) {
- if (MakeDirs(macName))
- goto again_file;
-
- PgmAlert(routine, "\pCould not make file", macName);
- errFound = SkipFile((long)hstat.st_size);
- break;
- }
-
- /*
- * Note that this only extracts data forks!
- */
- for (size = hstat.st_size;
- size > 0;
- size -= written) {
- /*
- * Locate data, determine max length
- * writeable, write it, record that
- * we have used the data, then check
- * if the write worked.
- */
- if ((rec = FindRec()) == nil)
- return(true);
-
- data = rec->charptr;
- written = EndOfRecs()->charptr - data;
- if (written > size)
- written = size;
-
- /*
- * Convert newlines to return for Mac compatability.
- */
- if (cvtNl) {
- for (i = written, p = data; --i >= 0; p++)
- if (*p == LF)
- *p = RETURN;
- }
-
- check = written;
- fpb.ioParam.ioBuffer = data;
- fpb.ioParam.ioReqCount = check;
- fpb.ioParam.ioPosMode = fsAtMark;
- fpb.ioParam.ioPosOffset = 0;
- err = PBWrite((ParmBlkPtr) &fpb, false);
- if (err != noErr) {
- OSAlert(routine, "\pPBWrite", macName, err);
- goto doNext;
- }
-
- check = fpb.ioParam.ioActCount;
- /*
- * The following is in violation of strict
- * typing, since the arg to userec
- * should be a struct rec *. FIXME.
- */
- UseRec(data + written - 1);
- if (check == written)
- continue;
-
- /*
- * Error in writing to file.
- * Print it, skip to next file in archive.
- */
- PgmAlert(routine, "\pWrite short", macName);
- doNext:
- PBClose((ParmBlkPtr) &fpb, false);
- errFound = SkipFile((long)(size - written));
- goto quit;
- }
-
- PBClose((ParmBlkPtr) &fpb, false);
- quit:
- break;
-
- case LF_DIR:
- /* Check for trailing / */
- namelen = strlen(head->header.name)-1;
- really_dir:
- while (namelen && head->header.name[namelen] == '/')
- head->header.name[namelen--] = '\0'; /* Zap / */
-
- FixName(head->header.name, macName);
- /* FALL THROUGH */
- again_dir:
- dpb.fileParam.ioCompletion = nil;
- dpb.fileParam.ioNamePtr = macName;
- dpb.fileParam.ioVRefNum = dirVRefNum;
- dpb.fileParam.ioFVersNum = 0;
- dpb.fileParam.ioDirID = dirDirID;
- err = PBDirCreate(&dpb, false);
- if ((err != noErr) && (err != dupFNErr)) {
- if (MakeDirs(macName))
- goto again_dir;
-
- PgmAlert(routine, "\pCould not make directory", macName);
- }
-
- break;
- }
-
- /* We don't need to save it any longer. */
- SaveRec((union record **) 0);
- return(errFound);
- }
-
- /*
- * After a file/link/symlink/dir creation has failed, see if
- * it's because some required directory was not present, and if
- * so, create all required dirs.
- */
- int
- MakeDirs(pathname)
- char *pathname;
- {
- int madeone = 0; /* Did we do anything yet? */
- int i, savedLen;
- OSErr err;
- HParamBlockRec pb;
-
- savedLen = pathname[0] & 0xff;
- /*
- * skip initial ':'
- *
- * Note that the directory name has already been converted to Mac style.
- */
- for (i = 2; i < savedLen; i++) {
- while ((i < savedLen) && (pathname[i] != ':'))
- i++;
-
- if (i == savedLen)
- break;
-
- pathname[0] = i++ - 1;
- pb.fileParam.ioCompletion = nil;
- pb.fileParam.ioNamePtr = pathname;
- pb.fileParam.ioVRefNum = dirVRefNum;
- pb.fileParam.ioFVersNum = 0;
- pb.fileParam.ioDirID = dirDirID;
- err = PBDirCreate(&pb, false);
- if (err == dupFNErr) {
- continue;
-
- } else if (err != noErr) {
- OSAlert("\pMakeDirs", "\pPBDirCreate", pathname,
- pb.fileParam.ioResult);
- return(0);
-
- } else {
- madeone++; /* Remember if we made one */
- continue;
- }
- }
-
- pathname[0] = savedLen;
- return(madeone); /* Tell them to retry if we made one */
- }
-
- /*
- * FixName - convert to a Mac style pathname
- *
- * Conversions:
- * . -> (Stay at this directory level)
- * .. -> :: (Up a directory level)
- * .xxxx -> _xxxx (Don't get in trouble with device names)
- * xx:xx -> xx/xx (Don't get in trouble with directory delims)
- */
- FixName(tar, mac)
- register char *tar;
- char *mac;
- {
- char *end = tar + strlen(tar);
- register char *p = mac + 1;
- register char *next;
-
- for (next = tar; tar < end; next++) {
- /*
- * Swallow up all contiguous '/' characters.
- */
- while (*next && (*next == '/'))
- next++;
-
- /*
- * Find the entire name up until the next '/'.
- */
- tar = next;
- while (*next && (*next != '/'))
- next++;
-
- *next = 0;
- *p++ = ':';
- if (*tar == '.')
- switch (*(tar + 1)) {
- case '\0':
- p--;
- continue;
-
- case '.':
- if (*(tar + 2) == 0)
- continue;
- /* else FALL THROUGH */
-
- default:
- *tar = '_';
- }
-
- while (tar < next) {
- if (*tar == ':')
- *tar = '/';
- *p++ = *tar++;
- }
- }
-
- *mac = p - mac - 1;
- }
-